package org.gitee.weapp.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.gitee.weapp.domain.common.constant.Constant;
import org.gitee.weapp.domain.common.exception.WeChatException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class HttpUtils {

    private static final String WECHATSESSION = "https://api.weixin.qq.com/sns/jscode2session";


    private static final String WECHATACCESSTOKEN = "https://api.weixin.qq.com/cgi-bin/token";


    private static final String WECHATPHONE = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";

    private static final Object LOCK = new Object();

    @Value("${weapp.appId}")
    private String appId;

    @Value("${weapp.appSecret}")
    private String appSecret;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisCache redisCache;

    /**
     * 根据code获取openid
     * @param code code
     * @return
     */
    public JSONObject getCodeSession(String code) {
        StringBuffer sb = new StringBuffer(WECHATSESSION);
        sb.append('?').append("appid=").append(appId).append("&secret=").append(appSecret)
                .append("&js_code=").append(code).append("&grant_type=authorization_code");
        String body = restTemplate.getForObject(sb.toString(), String.class);
        log.info("body:" + body);
        return JSONObject.parseObject(body);
    }


    /**
     * 获取access_token
     * @param openId openId
     * @return access_token
     */
    public String getAccessToken(String openId) {
        String token = redisCache.getCacheObject(Constant.TOKEN_PREFIX + openId);
        if (null == token) {
            synchronized(LOCK) {
                token = redisCache.getCacheObject(Constant.TOKEN_PREFIX + openId);
                if (null != token) {
                    return token;
                }

                StringBuffer sb = new StringBuffer(WECHATACCESSTOKEN);
                sb.append('?').append("appid=").append(appId).append("&secret=").append(appSecret)
                        .append("&grant_type=client_credential");
                String body = restTemplate.getForObject(sb.toString(), String.class);
                log.info("body:" + body);

                JSONObject jsonObject = JSONObject.parseObject(body);
                String accessToken = jsonObject.getString("access_token");
                Integer expires = jsonObject.getInteger("expires_in");
                if (null == accessToken || null == expires) {
                    throw new WeChatException("获取token错误");
                }
                redisCache.setCacheObject(Constant.TOKEN_PREFIX + openId, accessToken, expires, TimeUnit.SECONDS);
                return accessToken;
            }
        }
        return token;
    }


    public String getPhone(String accessToken, String code) {
        StringBuffer sb = new StringBuffer(WECHATPHONE);
        sb.append('?').append("access_token=").append(accessToken);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        HttpEntity<Map<String, String>> formEntity = new HttpEntity<>(map, headers);
        String body = restTemplate.postForObject(sb.toString(), formEntity, String.class);
        JSONObject jsonObject = JSON.parseObject(body);
        JSONObject phoneObject = jsonObject.getJSONObject("phone_info");
        if (null != phoneObject) {
            return phoneObject.getString("phoneNumber");
        }
        return null;
    }
}
